package com.huiyeji.dynamic.core.bean;



import com.huiyeji.dynamic.core.DynamicContext;
import com.huiyeji.dynamic.core.DynamicStatement;
import com.huiyeji.dynamic.core.DynamicStatementPointer;
import com.huiyeji.dynamic.core.annotations.*;

import java.util.*;

/**
 * @author Huiyeji
 */
@DynamicBean("for")
public class DynamicFor {

    private final DynamicContext context;

    private final DynamicStatementPointer pointer;

    private final String objectName;

    private final List<?> list;

    private final Set<String> tempKeys = new HashSet<String>();

    private final String forDynamicObjectName;

    private int index = 0;

    private final int size;

    private final int startPos;

    private final int endPos;

    public DynamicFor(DynamicContext context,Object object,String objectName){
        this.context = context;
        this.objectName = objectName;
        this.pointer = context.getPointer();
        List<DynamicStatement> statements = pointer.getStatements();
        int currentPosition = pointer.getCurrentPosition();
        DynamicStatement currentStatement = statements.get(currentPosition);
        this.forDynamicObjectName = currentStatement.getDynamicResultName();
        List<Integer> startIndexList = new ArrayList<Integer>();
        List<Integer> endIndexList = new ArrayList<Integer>();
        for (int i = currentPosition + 1; i < statements.size(); i++) {
            DynamicStatement dynamicStatement = statements.get(i);
            if (this.forDynamicObjectName.equals(dynamicStatement.getDynamicObjectName())){
                if ("start".equals(dynamicStatement.getDynamicMethodName())){
                    startIndexList.add(i);
                } else if ("end".equals(dynamicStatement.getDynamicMethodName())){
                    endIndexList.add(i);
                    break;
                }
            }
        }

        if (startIndexList.size() != 1 || endIndexList.size() != 1){
            throw new RuntimeException("for statement error");
        }

        this.startPos = startIndexList.get(0);
        this.endPos = endIndexList.get(0);

        if (startPos >= endPos){
            throw new RuntimeException("for statement sort error");
        }

        if (object instanceof List){
            this.list = (List<?>) object;
            size = list.size();
        } else if (object instanceof Set){
            Set<?> set = (Set<?>) object;
            this.list = new ArrayList<>(set);
            size = set.size();
        } else if (object instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) object;
            size = map.size();
            this.list = new ArrayList<Map.Entry<?, ?>>(map.entrySet());
        } else if (object instanceof Integer) {
            this.list = null;
            this.size = (Integer) object;
        } else if (object.getClass().isArray()){
            this.list = Arrays.asList((Object[]) object);
            this.size = list.size();
        } else {
            throw new RuntimeException("对象无法迭代");
        }

//        if (size == 0){
//            throw new RuntimeException("对象size为0");
//        }
    }

    @DynamicMethod("start")
    public void _start() {
        if (size == 0){
            context.getPointer().setNextPosition(endPos + 1);
            return;
        }

        if (this.list == null){
            context.setObject(objectName,index);
            tempKeys.add(objectName);
        } else {
            Object o = list.get(index);
            if (o instanceof Map.Entry) {
                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                context.setObject(objectName + ".key",entry.getKey());
                context.setObject(objectName + ".value",entry.getValue());
                tempKeys.add(objectName + ".key");
                tempKeys.add(objectName + ".value");
            } else {
                context.setObject(objectName,o);
                tempKeys.add(objectName);
            }
        }

    }

    @DynamicMethod("end")
    public void _end() {
        index++;
        if (index < size){
            this.pointer.setNextPosition(startPos);
        } else {
            globalClear();
        }
        tempClear();
    }

    @DynamicMethod("break")
    public void _break() {
        globalClear();
        tempClear();
        this.pointer.setNextPosition(endPos + 1);
    }

    @DynamicMethod("continue")
    public void _continue() {
        this.pointer.setNextPosition(endPos);
    }

    private void tempClear(){
        for (String tempKey : this.tempKeys) {
            this.context.removeObject(tempKey);
        }
        this.tempKeys.clear();
    }

    private void globalClear(){
        this.context.removeObject(forDynamicObjectName);
        this.context.getFactory().removeDynamicObject(forDynamicObjectName);
    }
}
